package com.mars.component.scheduler.utlis;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.mars.common.spring.SpringContextHolder;
import com.mars.component.scheduler.constant.SchedulerConst;
import com.mars.component.scheduler.entity.SchedulerTask;
import com.mars.component.scheduler.exception.SchedulerJobException;
import com.mars.component.scheduler.utlis.spring.ScheduleJob;

/**
 * Scheduler工具类
 * @类名 SchedulerUtils
 * @日期 2016年12月29日 上午9:05:36
 * @作者 yhaoquan
 * @版权 (c) All Rights Reserved, 2016.
 */
@Component
public class SchedulerUtils {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass()) ;
	
	/**
	 * JobId前缀
	 */
	private final static String JOB_NAME = "TASK_";
	
	@Autowired
	private Scheduler scheduler ;
	
	
	/**
     * 获取触发器key
     */
    public static TriggerKey getTriggerKey(Long jobId, String group) {
    	if(null != group) {
    		return TriggerKey.triggerKey(JOB_NAME + jobId, group) ;
    	} else {
    		return TriggerKey.triggerKey(JOB_NAME + jobId);
    	}
    }
    
    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(Long jobId, String group) {
    	if(null != group) {
    		return JobKey.jobKey(JOB_NAME + jobId, group);
    	} else {
    		return JobKey.jobKey(JOB_NAME + jobId);
    	}
    }

    /**
     * 获取表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId, String group) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId, group));
        } catch (SchedulerException e) {
            throw SchedulerJobException.CRON_TRIGGER_EXCEPTION.logError(e);
        }
    }
	
	/**
	 * 创建任务调度，运行的类需要实现Quartz的Job接口
	 * @param task
	 * 			className属性值不能为空
	 */
    public void createScheduleJob(SchedulerTask task) {
    	try {
    		//1: 构建Job信息，运行的类需要实现Job接口
    		JobDetail jobDetail = JobBuilder.newJob(getClass(task.getClassName())).withIdentity(getJobKey(task.getJobId(), task.getJobGroup())).build();
    		//1.1: 放入参数，运行时的方法可以获取
			jobDetail.getJobDataMap().put(SchedulerTask.JOB_PARAM_KEY, task);
    		
    		//2: 表达式调度构建器
    		CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(task.getCronExpression()) ;
    		
    		//3: 按新的cronExpression表达式构建一个新的trigger
    		CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(task.getJobId(), task.getJobGroup())).withSchedule(cronSchedule).build() ;
    		
    		//4: 创建任务调度
    		this.scheduler.scheduleJob(jobDetail, trigger) ;
    		
    		//设置任务状态
    		if(task.getStatus() == SchedulerConst.ScheduleStatus.PAUSE.getValue()) {
    			pauseJob(task);
    		}
    		
    		logger.info("任务创建成功【任务状态：{}   任务ID： {}   任务运行BeanName：{}   任务运行的方法：{}   任务触发表达式：{}】", 
					SchedulerConst.ScheduleStatus.getEnum((null==task.getStatus()?0:task.getStatus())).getDesc(),
					jobDetail.getKey(),
					task.getBeanName(),
					task.getMethodName(),
					task.getCronExpression());
    		
    	} catch (Exception e) {
    		throw SchedulerJobException.CREATE_SCHEDULER_FAILED.logError(e) ;
    	}
    }
    
    /**
     * 通过Spring方式来运行任务
     * @param task
     * 			task.beanName 不能未空
     * 			task.methodName 不能未空
     * 
     */
	public void createScheduleJob4Spring(SchedulerTask task) {
		try {
			//1: 构建Job信息，运行的类需要实现Job接口
			JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(task.getJobId(), task.getJobGroup())).build();
			//1.1: 放入参数，运行时的方法可以获取
			jobDetail.getJobDataMap().put(SchedulerTask.JOB_PARAM_KEY, task);
			
			//2: 表达式调度构建器
			CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(task.getCronExpression()) ;
			
			//3: 按新的cronExpression表达式构建一个新的trigger
			CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(task.getJobId(), task.getJobGroup())).withSchedule(cronSchedule).build() ;
			
			//4: 创建任务调度
			this.scheduler.scheduleJob(jobDetail, trigger) ;
			
			//设置任务状态
			if(null != task.getStatus() && task.getStatus() == SchedulerConst.ScheduleStatus.PAUSE.getValue()) {
				pauseJob(task);
			}
			
			logger.info("任务创建成功【任务状态：{}   任务ID： {}   任务运行类：{}   任务运行的方法：{}   任务触发表达式：{}】", 
					SchedulerConst.ScheduleStatus.getEnum((null==task.getStatus()?0:task.getStatus())).getDesc(),
					jobDetail.getKey(),
					SpringContextHolder.getBean(task.getBeanName()).getClass(),
					task.getMethodName(),
					task.getCronExpression());
		} catch (Exception e) {
			e.printStackTrace();
			throw SchedulerJobException.CREATE_SCHEDULER_FAILED.logError(e) ;
		}
	}
	
	/**
	 * 修改任务调度的触发时间
	 * @param task
	 */
	public void rescheduleJob(SchedulerTask task) {
		try {
            TriggerKey triggerKey = getTriggerKey(task.getJobId(), task.getJobGroup());

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCronExpression());

            CronTrigger trigger = getCronTrigger(scheduler, task.getJobId(), task.getJobGroup());
            
            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            
            //参数
            trigger.getJobDataMap().put(SchedulerTask.JOB_PARAM_KEY, task);
            
            scheduler.rescheduleJob(triggerKey, trigger);
            
            //设置任务状态
            if(null != task.getStatus() && task.getStatus() == SchedulerConst.ScheduleStatus.PAUSE.getValue()) {
				pauseJob(task);
			}
            
        } catch (SchedulerException e) {
            throw new SchedulerJobException("更新定时任务失败", e);
        }
	}
	
	/**
	 * 暂停任务调度
	 * @param task
	 */
	public void pauseJob(SchedulerTask task) {
		try {
            scheduler.pauseJob(getJobKey(task.getJobId(), task.getJobGroup()));
        } catch (SchedulerException e) {
            throw new SchedulerJobException("暂停定时任务失败", e);
        }
	}
	
	/**
	 * 恢复任务调度
	 * @param task
	 */
	public void resumeJob(SchedulerTask task) {
		try {
            scheduler.resumeJob(getJobKey(task.getJobId(), task.getJobGroup()));
        } catch (SchedulerException e) {
            throw new SchedulerJobException("暂停定时任务失败", e);
        }
	}
	
	/**
	 * 删除任务
	 * @param task
	 */
	public void deleteJob(SchedulerTask task) {
		try {
            scheduler.deleteJob(getJobKey(task.getJobId(), task.getJobGroup()));
        } catch (SchedulerException e) {
            throw new SchedulerJobException("删除定时任务失败", e);
        }
	}
	
	@SuppressWarnings("unchecked")
	private Class<Job> getClass(String taskClassName)
			throws ClassNotFoundException {
		return (Class<Job>) Class.forName(taskClassName);
	}
	
}
